<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>152作用域和作用域链</title>
</head>

<body>
  <h1>152作用域和作用域链</h1>
  <script>
    /*
      学习目的：了解作用域对程序执行的影响和作用域链的查找机制，使用闭包函数创建隔离作用域避免全局污染问题。
      一、作用域scope(规定了变量能够被访问的“范围”，离开了这个“范围”变量不能被访问)
        1 局部作用域
          函数作用域
            在函数内部声明的变量只能在函数内部被访问，外部无法直接访问。
            函数的形参也是函数内部的局部变量。
            不同函数内部声明的变量无法相互访问。
            函数执行完毕后，函数内部的变量实际被清空了。

          块级作用域(配合let和const)
            被{}包裹的代码被称为代码块，在代码块中声明的变量外部有可能无法访问。
            let和const声明的变量都会产生块级作用域。
            不同代码块中的变量无法相互访问。

        2 全局作用域
          script标签和外部js文件的最外层就是所谓的全局作用域。全局作用域中声明的变量在局部作用域内均可直接使用。
          给window对象添加的属性默认也是全局的。
          函数中未使用任何关键词声明的变量为全局变量。
          实际开发中，尽可能少声明全局变量，避免全局污染。
      
      二、作用域链
        作用域链的本质就是变量的查找机制。
        执行函数时，会优先查找函数内部的变量，如果没有，再依次逐级查找父级作用域中的变量，直到全局作用域为止。
    */
    function fn(x, y) {
      let a = 'lqj'
    }
    fn(1, 2)
    // console.log(a) // 报错，name是局部变量，在局部作用域内，外部无法直接访问。
    // console.log(x) // 报错，x是函数fn的形参，也是在局部作用域内，，外部无法直接访问。

    for (let i = 0; i < 3; i++) {
      console.log('i=>' + i)
    }
    // console.log(i) // 报错，let声明的变量i在块级作用域内，外部无法访问。

    for (var j = 0; j < 3; j++) {
      console.log('j=>' + j)
    }
    console.log('j=>' + j) // 3，var声明的变量j没有块级作用域，因此外部可以正常访问。

    // 变量k拥有块级作用域，因此两个for循环的k互不干扰。
    for (let k = 0; k < 3; k++) {
      console.log('k=>' + k)
    }
    for (let k = 0; k < 3; k++) {
      console.log('k=>' + k)
    }

    function foo() {
      b = 1 // b是全局变量
    }
    foo()
    console.log('b=>' + b)
  </script>
</body>

</html>